"""
视频配音API接口
"""

from fastapi import APIRouter, HTTPException, status, Depends, BackgroundTasks, UploadFile, File, Form
from fastapi.responses import FileResponse
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any
import os
from datetime import datetime

from ...core.exceptions import (
    ValidationError, 
    NotFoundError,
    BusinessLogicError,
    FileOperationError,
    VideoProcessingError,
    with_error_handling
)
from ...core.security import (
    get_current_user,
    rate_limit,
    require_permission
)
from ...core.logging import audit_logger
from ...core.config import settings
from ...services.video import (
    VideoProcessor,
    VideoDubber,
    DubbingMode,
    DubbingSegment,
    DubbingRequest,
    DubbingResult
)
from ...services.tts import tts_service, VoiceProfile, VoiceSettings


# 创建路由
router = APIRouter()

# 全局实例
video_processor = VideoProcessor()
video_dubber = VideoDubber()


# 请求模型
class DubbingSegmentModel(BaseModel):
    """配音片段模型"""
    text: str = Field(..., min_length=1, max_length=5000, description="配音文本")
    start_time: float = Field(..., ge=0.0, description="开始时间（秒）")
    end_time: float = Field(..., ge=0.0, description="结束时间（秒）")
    voice_id: Optional[str] = Field(None, description="语音ID")
    voice_preset: Optional[str] = Field(None, description="语音预设")
    volume: float = Field(1.0, ge=0.0, le=2.0, description="音量")
    sync_offset: float = Field(0.0, ge=-10.0, le=10.0, description="同步偏移")


class VideoDubbingRequestModel(BaseModel):
    """视频配音请求模型"""
    video_path: str = Field(..., description="视频文件路径")
    segments: List[DubbingSegmentModel] = Field(..., min_items=1, max_items=100, description="配音片段列表")
    output_path: Optional[str] = Field(None, description="输出文件路径")
    mode: str = Field("replace", pattern="^(replace|overlay|mixed|narration)$", description="配音模式")
    voice_settings: Optional[Dict[str, Any]] = Field(None, description="语音设置")
    enhancement_settings: Optional[Dict[str, Any]] = Field(None, description="音频增强设置")
    sync_method: str = Field("audio_peaks", pattern="^(audio_peaks|video_motion|cross_correlation|lip_sync|manual)$", description="同步方法")
    original_audio_volume: float = Field(0.3, ge=0.0, le=1.0, description="原音频音量")
    dubbing_audio_volume: float = Field(1.0, ge=0.0, le=2.0, description="配音音量")


class AutoDubbingRequestModel(BaseModel):
    """自动配音请求模型"""
    video_path: str = Field(..., description="视频文件路径")
    text: str = Field(..., min_length=10, max_length=50000, description="配音文本")
    output_path: Optional[str] = Field(None, description="输出文件路径")
    mode: str = Field("replace", pattern="^(replace|overlay|mixed|narration)$", description="配音模式")
    voice_id: Optional[str] = Field(None, description="语音ID")
    voice_preset: Optional[str] = Field(None, description="语音预设")
    max_segment_duration: float = Field(10.0, ge=1.0, le=30.0, description="最大片段时长")
    voice_settings: Optional[Dict[str, Any]] = Field(None, description="语音设置")
    sync_method: str = Field("audio_peaks", pattern="^(audio_peaks|video_motion|cross_correlation|lip_sync|manual)$", description="同步方法")


class VideoInfoRequestModel(BaseModel):
    """视频信息请求模型"""
    video_path: str = Field(..., description="视频文件路径")


# 响应模型
class VideoInfoModel(BaseModel):
    """视频信息模型"""
    path: str
    duration: float
    fps: float
    width: int
    height: int
    channels: int
    audio_sample_rate: Optional[int]
    audio_channels: Optional[int]
    format: str
    file_size: int
    has_audio: bool


class DubbingResultModel(BaseModel):
    """配音结果模型"""
    success: bool
    output_path: Optional[str]
    duration: Optional[float]
    segments_processed: int
    metadata: Optional[Dict[str, Any]]
    error_message: Optional[str]


# API端点
@router.post("/upload")
@with_error_handling("upload_video")
@rate_limit(limit=5, window=300)  # 每5分钟5个视频
@require_permission("upload_video")
async def upload_video(
    background_tasks: BackgroundTasks,
    file: UploadFile = File(..., description="视频文件"),
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """上传视频文件"""
    try:
        # 验证文件类型
        if not file.content_type or not file.content_type.startswith('video/'):
            raise ValidationError("只能上传视频文件")
        
        # 生成文件名
        import uuid
        timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S")
        unique_id = str(uuid.uuid4())[:8]
        
        # 获取文件扩展名
        file_ext = os.path.splitext(file.filename)[1]
        if not file_ext:
            raise ValidationError("文件名必须有扩展名")
        
        filename = f"video_{timestamp}_{unique_id}{file_ext}"
        file_path = os.path.join(settings.UPLOAD_DIR, filename)
        
        # 保存文件
        def save_file():
            with open(file_path, "wb") as buffer:
                content = file.file.read()
                buffer.write(content)
        
        background_tasks.add_task(save_file)
        
        # 验证视频文件
        if not video_processor.validate_video_file(file_path):
            # 异步删除无效文件
            def cleanup_file():
                if os.path.exists(file_path):
                    os.unlink(file_path)
            background_tasks.add_task(cleanup_file)
            
            raise ValidationError("无效的视频文件")
        
        # 记录审计日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="upload_video",
            resource="video",
            details={
                "filename": filename,
                "original_filename": file.filename,
                "file_size": file.size
            }
        )
        
        return {
            "success": True,
            "message": "视频上传成功",
            "file_path": file_path,
            "filename": filename,
            "file_size": file.size
        }
        
    except Exception as e:
        if isinstance(e, (ValidationError, FileOperationError)):
            raise
        raise FileOperationError(f"上传视频失败: {str(e)}")


@router.post("/info", response_model=VideoInfoModel)
@with_error_handling("get_video_info")
@rate_limit(limit=20, window=60)
async def get_video_info(
    request: VideoInfoRequestModel,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """获取视频信息"""
    try:
        if not os.path.exists(request.video_path):
            raise NotFoundError(f"视频文件 {request.video_path} 不存在")
        
        video_info = video_processor.get_video_info(request.video_path)
        
        return VideoInfoModel(
            path=video_info.path,
            duration=video_info.duration,
            fps=video_info.fps,
            width=video_info.width,
            height=video_info.height,
            channels=video_info.channels,
            audio_sample_rate=video_info.audio_sample_rate,
            audio_channels=video_info.audio_channels,
            format=video_info.format,
            file_size=video_info.file_size,
            has_audio=video_info.has_audio
        )
        
    except Exception as e:
        if isinstance(e, NotFoundError):
            raise
        raise VideoProcessingError(f"获取视频信息失败: {str(e)}")


@router.post("/dubbing", response_model=DubbingResultModel)
@with_error_handling("create_dubbing")
@rate_limit(limit=2, window=300)  # 每5分钟2个配音任务
@require_permission("create_dubbing")
async def create_dubbing(
    request: VideoDubbingRequestModel,
    background_tasks: BackgroundTasks,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """创建视频配音"""
    # 记录审计日志
    audit_logger.log_user_action(
        user_id=current_user.get("sub"),
        action="create_dubbing",
        resource="video",
        details={
            "video_path": request.video_path,
            "segments_count": len(request.segments),
            "mode": request.mode
        }
    )
    
    try:
        # 验证视频文件
        if not os.path.exists(request.video_path):
            raise NotFoundError(f"视频文件 {request.video_path} 不存在")
        
        if not video_processor.is_supported_format(request.video_path):
            raise ValidationError(f"不支持的视频格式: {request.video_path}")
        
        # 检查配音器是否初始化
        if not video_dubber._initialized:
            await video_dubber.initialize()
        
        # 生成输出路径
        if not request.output_path:
            output_path = await _generate_dubbing_output_path(request.video_path, request.mode)
        else:
            output_path = request.output_path
        
        # 转换配音片段
        segments = []
        for seg_model in request.segments:
            # 获取语音配置
            voice_profile = None
            if seg_model.voice_id:
                voices = await tts_service.get_available_voices()
                voice_profile = next((v for v in voices if v.id == seg_model.voice_id), None)
            
            segment = DubbingSegment(
                text=seg_model.text,
                start_time=seg_model.start_time,
                end_time=seg_model.end_time,
                voice_profile=voice_profile,
                volume=seg_model.volume,
                sync_offset=seg_model.sync_offset
            )
            segments.append(segment)
        
        # 创建配音请求
        voice_settings = None
        if request.voice_settings:
            voice_settings = VoiceSettings(**request.voice_settings)
        
        dubbing_request = DubbingRequest(
            video_path=request.video_path,
            segments=segments,
            output_path=output_path,
            mode=DubbingMode(request.mode),
            voice_settings=voice_settings,
            enhancement_settings=request.enhancement_settings,
            sync_method=request.sync_method,
            original_audio_volume=request.original_audio_volume,
            dubbing_audio_volume=request.dubbing_audio_volume
        )
        
        # 执行配音（后台任务）
        background_tasks.add_task(
            _process_dubbing_request,
            dubbing_request,
            current_user.get("sub")
        )
        
        return DubbingResultModel(
            success=True,
            output_path=output_path,
            duration=0.0,  # 将在后台任务中更新
            segments_processed=len(segments),
            metadata={
                "status": "processing",
                "video_path": request.video_path,
                "mode": request.mode
            }
        )
        
    except Exception as e:
        if isinstance(e, (ValidationError, NotFoundError, VideoProcessingError)):
            raise
        raise VideoProcessingError(f"创建配音失败: {str(e)}")


@router.post("/auto-dubbing", response_model=DubbingResultModel)
@with_error_handling("create_auto_dubbing")
@rate_limit(limit=2, window=300)  # 每5分钟2个自动配音任务
@require_permission("create_dubbing")
async def create_auto_dubbing(
    request: AutoDubbingRequestModel,
    background_tasks: BackgroundTasks,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """创建自动视频配音"""
    # 记录审计日志
    audit_logger.log_user_action(
        user_id=current_user.get("sub"),
        action="create_auto_dubbing",
        resource="video",
        details={
            "video_path": request.video_path,
            "text_length": len(request.text),
            "mode": request.mode
        }
    )
    
    try:
        # 验证视频文件
        if not os.path.exists(request.video_path):
            raise NotFoundError(f"视频文件 {request.video_path} 不存在")
        
        # 检查配音器是否初始化
        if not video_dubber._initialized:
            await video_dubber.initialize()
        
        # 生成输出路径
        output_path = await _generate_dubbing_output_path(request.video_path, request.mode)
        
        # 自动创建配音片段
        segments = await video_dubber.create_auto_segments(
            request.video_path,
            request.text,
            request.max_segment_duration
        )
        
        if not segments:
            raise ValidationError("无法创建有效的配音片段")
        
        # 应用语音配置到所有片段
        if request.voice_id or request.voice_preset:
            voices = await tts_service.get_available_voices()
            voice_profile = None
            
            if request.voice_id:
                voice_profile = next((v for v in voices if v.id == request.voice_id), None)
            
            for segment in segments:
                segment.voice_profile = voice_profile
        
        # 创建配音请求
        voice_settings = None
        if request.voice_settings:
            voice_settings = VoiceSettings(**request.voice_settings)
        
        dubbing_request = DubbingRequest(
            video_path=request.video_path,
            segments=segments,
            output_path=output_path,
            mode=DubbingMode(request.mode),
            voice_settings=voice_settings,
            sync_method=request.sync_method
        )
        
        # 执行配音（后台任务）
        background_tasks.add_task(
            _process_dubbing_request,
            dubbing_request,
            current_user.get("sub")
        )
        
        return DubbingResultModel(
            success=True,
            output_path=output_path,
            duration=0.0,  # 将在后台任务中更新
            segments_processed=len(segments),
            metadata={
                "status": "processing",
                "video_path": request.video_path,
                "mode": request.mode,
                "auto_generated": True
            }
        )
        
    except Exception as e:
        if isinstance(e, (ValidationError, NotFoundError, VideoProcessingError)):
            raise
        raise VideoProcessingError(f"创建自动配音失败: {str(e)}")


@router.get("/download/{filename}")
@with_error_handling("download_dubbed_video")
@rate_limit(limit=10, window=300)  # 每5分钟10次下载
async def download_dubbed_video(
    filename: str,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """下载配音视频"""
    try:
        file_path = os.path.join(settings.UPLOAD_DIR, filename)
        
        if not os.path.exists(file_path):
            raise NotFoundError(f"配音视频文件 {filename} 不存在")
        
        # 验证文件是否为视频文件
        if not video_processor.is_supported_format(file_path):
            raise ValidationError("无效的视频文件")
        
        # 记录下载日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="download_dubbed_video",
            resource="video",
            details={"filename": filename}
        )
        
        return FileResponse(
            path=file_path,
            filename=filename,
            media_type="video/mp4"
        )
        
    except Exception as e:
        if isinstance(e, (NotFoundError, ValidationError)):
            raise
        raise FileOperationError(f"下载配音视频失败: {str(e)}")


@router.get("/thumbnail/{filename}")
@with_error_handling("get_video_thumbnail")
async def get_video_thumbnail(
    filename: str,
    timestamp: float = 1.0,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """获取视频缩略图"""
    try:
        file_path = os.path.join(settings.UPLOAD_DIR, filename)
        
        if not os.path.exists(file_path):
            raise NotFoundError(f"视频文件 {filename} 不存在")
        
        # 生成缩略图
        thumbnail_path = video_processor.get_video_thumbnail(file_path, timestamp=timestamp)
        
        return FileResponse(
            path=thumbnail_path,
            filename=f"thumbnail_{filename.replace('.', '_')}.jpg",
            media_type="image/jpeg"
        )
        
    except Exception as e:
        if isinstance(e, NotFoundError):
            raise
        raise VideoProcessingError(f"获取视频缩略图失败: {str(e)}")


@router.get("/formats")
@with_error_handling("get_supported_formats")
async def get_supported_formats(
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """获取支持的视频格式"""
    try:
        return {
            "input_formats": video_processor.supported_formats,
            "output_formats": ["mp4", "avi", "mov"],
            "dubbing_modes": ["replace", "overlay", "mixed", "narration"],
            "sync_methods": ["audio_peaks", "video_motion", "cross_correlation", "lip_sync", "manual"]
        }
        
    except Exception as e:
        raise BusinessLogicError(f"获取支持格式失败: {str(e)}")


# 辅助函数
async def _generate_dubbing_output_path(video_path: str, mode: str) -> str:
    """生成配音输出路径"""
    import uuid
    from datetime import datetime
    
    timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S")
    unique_id = str(uuid.uuid4())[:8]
    
    # 获取原文件名（不含扩展名）
    base_name = os.path.splitext(os.path.basename(video_path))[0]
    
    filename = f"{base_name}_dubbed_{mode}_{timestamp}_{unique_id}.mp4"
    return os.path.join(settings.UPLOAD_DIR, filename)


async def _process_dubbing_request(
    request: DubbingRequest,
    user_id: str
):
    """处理配音请求（后台任务）"""
    try:
        # 执行配音
        result = await video_dubber.create_dubbing(request)
        
        if result.success:
            # 记录成功日志
            audit_logger.log_user_action(
                user_id=user_id,
                action="dubbing_completed",
                resource="video",
                details={
                    "output_path": result.output_path,
                    "duration": result.duration,
                    "segments_processed": result.segments_processed
                }
            )
        else:
            # 记录失败日志
            audit_logger.log_user_action(
                user_id=user_id,
                action="dubbing_failed",
                resource="video",
                details={
                    "error_message": result.error_message,
                    "video_path": request.video_path
                }
            )
            
    except Exception as e:
        # 记录异常日志
        audit_logger.log_user_action(
            user_id=user_id,
            action="dubbing_error",
            resource="video",
            details={
                "error_message": str(e),
                "video_path": request.video_path
            }
        )
        print(f"处理配音请求失败: {e}")
